import java.math.BigDecimal;
import java.math.RoundingMode;

import org.apache.commons.math3.fitting.PolynomialCurveFitter;
import org.apache.commons.math3.fitting.WeightedObservedPoints;

/**
 * 多项式拟合
 * 
 * @author jianqing.liu
 * @since 2024年7月15日 下午6:28:23
 */
public class LeastSquaresExample
{
	private static final String[] SUPER_SCRIPT = { "⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹" };

	public static String getSuperScript(int i)
	{
		if (i < 10)
		{
			return SUPER_SCRIPT[i];
		}
		else
		{
			char[] chars = String.valueOf(i).toCharArray();
			StringBuilder superScript = new StringBuilder();
			for (char c : chars)
			{
				superScript.append(SUPER_SCRIPT[c - 48]);
			}
			return superScript.toString();
		}
	}

	public static void main(String[] args)
	{
		// 离散的点
		WeightedObservedPoints weightedObservedPoints = new WeightedObservedPoints();
		weightedObservedPoints.add(1.0, -2);
		weightedObservedPoints.add(2.0, -3);
		weightedObservedPoints.add(3.0, -4);
		weightedObservedPoints.add(4.0, -5);
		weightedObservedPoints.add(5.0, -6);
		weightedObservedPoints.add(6.0, -7);
		weightedObservedPoints.add(7.0, -8);
		weightedObservedPoints.add(8.0, -9);

		// 多项式曲线装配器
		// 传入参数 2 表示该多项式是 一元二次 函数
		PolynomialCurveFitter polynomialCurveFitter = PolynomialCurveFitter.create(10);

		// 检索拟合参数
		// 这是 最小二乘拟合 的核心操作
		// 最终得到一个 多项式系数 数组
		final double[] polynomialCoefficient = polynomialCurveFitter.fit(weightedObservedPoints.toList());

		// 打印一元二次函数
		StringBuilder polynomial = new StringBuilder("f(x) = ");
		for (int i = polynomialCoefficient.length - 1; i >= 0; i--)
		{
			// 处理计算机精度问题
			BigDecimal number = BigDecimal.valueOf(polynomialCoefficient[i]).setScale(10, RoundingMode.HALF_UP);
			// 多项式 中的 x 次幂
			String itemXPower = i > 0 ? "X" + getSuperScript(i) : "";
			String itemSymbol = number.doubleValue() > 0 ? " + " : " - ";
			if (i == polynomialCoefficient.length - 1)
			{
				if (number.abs().compareTo(BigDecimal.ONE) == 0 && !"".equals(itemXPower))
				{
					if (number.compareTo(BigDecimal.ZERO) < 0)
					{
						polynomial.append("-").append(itemXPower);
					}
					else
					{
						polynomial.append(itemXPower);
					}
				}
				else if (number.compareTo(BigDecimal.ZERO) != 0 && !"".equals(itemXPower))
				{
					polynomial.append(number.stripTrailingZeros().toPlainString() + itemXPower);
				}
			}
			else
			{
				if (number.compareTo(BigDecimal.ONE) == 0 && "".equals(itemXPower))
				{
					polynomial.append(itemSymbol).append(number.abs().stripTrailingZeros().toPlainString() + itemXPower);
				}
				else if (number.abs().compareTo(BigDecimal.ONE) == 0 && !"".equals(itemXPower))
				{
					polynomial.append(itemSymbol).append(itemXPower);
				}
				else if (number.compareTo(BigDecimal.ZERO) != 0)
				{
					// 带 x 的系数的项
					itemXPower = "".equals(itemXPower) ? "" : ("·" + itemXPower);
					polynomial.append(itemSymbol).append(number.abs().stripTrailingZeros().toPlainString() + itemXPower);
				}

			}
		}
		System.out.println("多项式函数 : " + polynomial);

	}
}
